﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Hosting;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using log4net;
using System.IO;

namespace SimpleMVC.Util
{
    public class Log4NetUtil
    {
        private static readonly ILog LogError;
        private static readonly bool CanLogError;
        private static readonly object ErrorLogLock = new object();
        private static readonly Queue<ErrorLogInfo> ErrorLogInfos = new Queue<ErrorLogInfo>();

        static Log4NetUtil()
        {
            string fileName = HostingEnvironment.MapPath("~/log4net.xml");
            var logStream = new FileStream(fileName, FileMode.Open);
            log4net.Config.XmlConfigurator.Configure(logStream);
            LogError = log4net.LogManager.GetLogger("logerror");
            if (LogError != null && LogError.IsErrorEnabled)
            {
                CanLogError = true;
            }
            else
            {
                CanLogError = false;
            }
            Work();
        }

        private static void Work()
        {
            if (CanLogError)
            {
                var terror = new Task(WriteError);
                terror.Start();
            }
        }

        public class ErrorLogInfo
        {
            public string Info { set; get; }
            public Exception Error { set; get; }
        }

        public static void WriteError()
        {
            while (true)
            {
                try
                {
                    if (ErrorLogInfos != null && ErrorLogInfos.Count > 0)
                    {
                        ErrorLogInfo errorLogInfo = null;
                        lock (ErrorLogLock)
                        {
                            try
                            {
                                errorLogInfo = ErrorLogInfos.Dequeue();
                            }
                            catch (Exception ex)
                            {
                                errorLogInfo = null;
                            }

                        }
                        if (errorLogInfo != null)
                        {
                            if (errorLogInfo.Error != null)
                            {
                                var e = errorLogInfo.Error.GetBaseException();
                                StringBuilder sb = new StringBuilder();
                                if (!string.IsNullOrEmpty(errorLogInfo.Info))
                                {
                                    sb.AppendFormat("<span style='color: red; font-weight: bold;'>{0}</span><BR/>",
                                        errorLogInfo.Info);
                                }
                                sb.AppendFormat(
                                    "<span style = 'background-color: gainsboro; font-weight: bold;'>{0}</span ><BR/>",
                                    e.Message);
                                if (!string.IsNullOrEmpty(e.StackTrace))
                                {
                                    sb.AppendFormat(e.StackTrace.Replace("\r\n", "<BR/>"));
                                }
                                string info = sb.ToString();
                                LogError.Error(info);
                            }
                            else
                            {
                                LogError.Error("<span style='color: red; font-weight: bold;'>" + errorLogInfo.Info +
                                               "</span>");
                            }
                        }
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }

        public static void Error(string info)
        {
            if (CanLogError)
            {
                ErrorLogInfo errorLogInfo = new ErrorLogInfo {Info = info};
                lock (ErrorLogLock)
                {
                    ErrorLogInfos.Enqueue(errorLogInfo);
                }
            }
        }

        public static void Error(string info, Exception e)
        {
            if (CanLogError)
            {
                ErrorLogInfo errorLogInfo = new ErrorLogInfo {Info = info, Error = e};
                lock (ErrorLogLock)
                {
                    ErrorLogInfos.Enqueue(errorLogInfo);
                }
            }
        }
    }
}